package org.streets.eis.component.navigatorbar;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.link.AbstractLink;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.markup.html.panel.Panel;
import org.streets.eis.component.dropdown.ToolBar;
import org.streets.eis.component.model.DataModel;
import org.streets.eis.component.model.MenuItem;


public abstract class NavigatorBar<T extends Serializable> extends Panel {
	private static final long serialVersionUID = 1L;
	
	public static enum PostType{
		NONE,
		ADD,
		REPLACE
	}
	
	private List<T> itemList = new ArrayList<T>();
	
	private int currentIndex = -1;
	
	private WebMarkupContainer bar;
	
	private String bgColor = "#e7f1f8";
	
	private String color = "#00000";
	
	private T currentItem = null;
	
	/**
	 * 是否显示增加按钮，为true时须继承onAdd方法 
	 */
	private boolean showAddButton = true;
	
	/**
	 * 是否显示删除按钮，为true时须继承onRemove方法 
	 */
	private boolean showRemoveButton = true;

	/**
	 * 是否显示替换按钮，为true时须继承onReplace方法 
	 */	
	private boolean showReplaceButton = true;

	/**
	 * 是否显示关闭按钮，为true时须继承onClose方法 
	 */		
	private boolean showCloseButton = true;
	
	public NavigatorBar(String id,T emptyItem) {
		super(id);
		setRenderBodyOnly(true);
		currentItem = emptyItem;
	}	
	
	public NavigatorBar(String id,List<T> list) {
		this(id,list,0);
	}
	
	public NavigatorBar(String id,List<T> list,int currentIndex) {
		super(id);
		setRenderBodyOnly(true);
		if (list==null || list.size()==0){
			throw new RuntimeException("NavigatorBar cannot  instantiate with empty list.");
		}
		itemList.addAll(list);
		if (validIndex(currentIndex)){
			this.currentIndex = currentIndex;
		} else {
			this.currentIndex = 0;
		}
		currentItem = cloneItem(itemList.get(currentIndex));		
	}	

	protected Label newPagedLabel(String id){
		int count = itemList.size();
		StringBuffer model = new StringBuffer("(");
		model.append(currentIndex>=0 ? currentIndex+1 : 0);
		model.append("/");
		model.append(count>=0 ? count : 0);
		model.append(")");
		return new Label(id,model.toString());
	}
	
	protected ToolBar newToolBar(String id){
		return new ToolBar(id,getDefaultToolBarDataModel()){
			private static final long serialVersionUID = 1L;
			@Override
			protected boolean needFormSubmitted(MenuItem menuItem){
				String code = menuItem.getCode();
				return "add".equals(code) || "replace".equals(code);
			}
			@Override
			protected void onMenuItemClicked(AbstractLink link,DataModel<MenuItem> dataModel,AjaxRequestTarget target){
				NavigatorBar.this.onToolButtonClicked(link,dataModel,target);
        	}
			@Override
			protected void beforeFormSubmit(DataModel<MenuItem> clickedItem,Form<?> form){
				PostType pt = PostType.NONE;
				String code = clickedItem.getObject().getCode();
				if ("add".equals(code)){
					pt = PostType.ADD;
				}
				if ("replace".equals(code)){
					pt = PostType.REPLACE;
				}
				NavigatorBar.this.beforeFormSubmit(form,pt,clickedItem);
			}
		};
	}
	
	public DataModel<MenuItem> getDefaultToolBarDataModel(){
		DataModel<MenuItem> model = new DataModel<MenuItem>();
		if (showAddButton){
			model.addChild(new DataModel<MenuItem>(new MenuItem("add","add","增加")));
		}
		if (showRemoveButton){
			model.addChild(new DataModel<MenuItem>(new MenuItem("remove","remove","删除")));
		}
		if (showReplaceButton){
			model.addChild(new DataModel<MenuItem>(new MenuItem("replace","replace","替换")));
		}
		model.addChild(new DataModel<MenuItem>(new MenuItem("first","first","第一条")));
		model.addChild(new DataModel<MenuItem>(new MenuItem("previous","previous","上一条")));
		model.addChild(new DataModel<MenuItem>(new MenuItem("next","next","下一条")));
		model.addChild(new DataModel<MenuItem>(new MenuItem("last","last","最后条")));
		if (showCloseButton){
			model.addChild(new DataModel<MenuItem>(new MenuItem("close","close","关闭")));
		}
		return model;
	}

	@Override
	protected void onBeforeRender(){
		
		if (bar!=null)	remove("bar");
		
		bar = new WebMarkupContainer("bar"){
			private static final long serialVersionUID = 1L;

			@Override
			protected void onComponentTag(final ComponentTag tag){
				super.onComponentTag(tag);
				tag.put("style", "background-color:" + NavigatorBar.this.bgColor + ";color:"+NavigatorBar.this.color);
			}
		};
		add(bar);
		bar.add(newPagedLabel("pagedLabel"));
		ToolBar toolbar = newToolBar("toolbar");
		bar.add(toolbar);
		
		
		DataModel<MenuItem> model = toolbar.getMenuModel();
		for (DataModel<MenuItem> child: model.getChildren()){
			setToolButtonStatus(child);			
		}
		super.onBeforeRender();
	}
	
	protected void setToolButtonStatus(DataModel<MenuItem> button){
		String code = button.getObject().getCode();
		if ("remove".equals(code)||"replace".equals(code)){
			button.getObject().setDisabled(!validIndex(currentIndex));
		} 
		if ("first".equals(code)||"previous".equals(code)){
			button.getObject().setDisabled(!validIndex(currentIndex)||currentIndex==0);
		}
		if ("next".equals(code)||"last".equals(code)){
			button.getObject().setDisabled(!validIndex(currentIndex)||currentIndex==itemList.size()-1);
		}
	}
		
	public void removeItem(T item){
		int idx = itemList.indexOf(item);
		if (validIndex(idx)){
			if (!canRemove(item)) return;
			onRemove(item);
			itemList.remove(item);
			if (!validIndex(idx)){
				idx = itemList.size() - 1;
			}
			showItem(idx);
		}
	}

	public void removeItem(int index){
		if (validIndex(index)){
			T item = itemList.get(index);	
			removeItem(item);
		}
	}
	
	protected boolean validIndex(int index){
		return index >= 0 && index < itemList.size();
	}
	
	public int getCurrentIndex() {
		return currentIndex;
	}

	public void setCurrentIndex(int currentIndex) {
		if (validIndex(currentIndex)){
			showItem(currentIndex);
		}
	}
	
	public String getBgColor() {
		return bgColor;
	}

	public NavigatorBar<T> setBgColor(String bgColor) {
		this.bgColor = bgColor;
		return this;
	}

	public String getColor() {
		return color;
	}

	public NavigatorBar<T> setColor(String color) {
		this.color = color;
		return this;
	}
	
	public boolean isShowAddButton() {
		return showAddButton;
	}

	public NavigatorBar<T> setShowAddButton(boolean showAddButton) {
		this.showAddButton = showAddButton;
		return this;
	}
	
	public boolean isShowRemoveButton() {
		return showRemoveButton;
	}

	public NavigatorBar<T> setShowRemoveButton(boolean showRemoveButton) {
		this.showRemoveButton = showRemoveButton;
		return this;
	}
	
	public boolean isShowReplaceButton() {
		return showReplaceButton;
	}

	public NavigatorBar<T> setShowReplaceButton(boolean showReplaceButton) {
		this.showReplaceButton = showReplaceButton;
		return this;
	}

	public boolean isShowCloseButton() {
		return showCloseButton;
	}

	public NavigatorBar<T> setShowCloseButton(boolean showCloseButton) {
		this.showCloseButton = showCloseButton;
		return this;
	}		
	
	protected void showItem(int index){
		currentItem = null;
		if (validIndex(index)){
			currentIndex = index;
			currentItem = cloneItem(itemList.get(currentIndex));			
		} else {
			currentIndex = -1;
		}
		onShow(currentItem);
	}
	
	public T getCurrentItem(){
		return currentItem;
	}
	
	public void update(){
		AjaxRequestTarget target = AjaxRequestTarget.get();
		if (target!=null){
			target.addComponent(getPage());
		}
	}
	
	protected void onToolButtonClicked(AbstractLink link,DataModel<MenuItem> dataModel,AjaxRequestTarget target){
		String code = dataModel.getObject().getCode();
		if ("add".equals(code)){
			onAdd(currentItem);
			itemList.add(currentItem);
			showItem(itemList.size()-1);
			update();
		}
		if ("remove".equals(code)){
			removeItem(currentIndex);
			update();
		}
		if ("replace".equals(code)){
			onReplace(currentItem);
			itemList.add(currentIndex, currentItem);
			itemList.remove(currentIndex+1);
			update();
		}
		if ("first".equals(code)){
			setCurrentIndex(0);
			update();
		}
		if ("previous".equals(code)){
			setCurrentIndex(currentIndex-1);
			update();
		}
		if ("next".equals(code)){
			setCurrentIndex(currentIndex+1);
			update();
		}
		if ("last".equals(code)){
			setCurrentIndex(itemList.size()-1);
			update();
		}
		if ("close".equals(code)){
			onClose(target);
		}
	}
	
	public void onValidateError(FeedbackPanel feedback){
		AjaxRequestTarget target = AjaxRequestTarget.get();
		if (target!=null){
			if (feedback!=null) target.addComponent(feedback);
		}	
	}
		
	/**
	 * index change（点击first/previous/next/last或新增等改变currentIndex值）时触发，设置显示内容
	 * 必须实现此方法
	 * @param item
	 */
	protected abstract void onShow(T item);

	/**
	 * 点击add按钮时触发，保存到数据库
	 * 显示add按钮时，必须重载此方法
	 * @param item
	 */	
	protected void onAdd(T item){
		
	}

	/**
	 * 点击replace按钮时触发，保存到数据库
	 * 显示replace按钮时，必须重载此方法
	 * @param item
	 */	
	protected void onReplace(T item){
		
	}
	
	/**
	 * 点击remove按钮时触发，从数据库或缓存中删除
	 * 显示remove按钮时，必须重载此方法
	 * @param item
	 */	
	protected void onRemove(T item){
		
	}
	
	/**
	 * 从数据库或缓存中删除之前触发
	 * @param item
	 */		
	protected boolean canRemove(T item){
		return true; 
	}
	
	/**
	 * 用作编辑场景时，必须重载实现；这样保持itemList里的数据不变，发生提交(add/replace)动作后更新itemList 
	 * @param item
	 */		
	protected T cloneItem(T item){
		return item;
	}
	
	/**
	 * 当add与replace共存时，form的validator需要根据动作不同而不同，重载实现不同的validate逻辑
	 * @param clickedItem
	 * @param form
	 */
	protected void beforeFormSubmit(final Form<?> form,final PostType postType,final DataModel<MenuItem> clickedItem){		
	}

	/**
	 * 点击关闭时触发，可用来关闭ModalWindow
	 * @param target
	 */	
	protected void onClose(final AjaxRequestTarget target){
		
	}
	
}
